package com.gl.battleship.services.managers;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.gl.battleship.domain.User;
import com.gl.battleship.domain.UserState;
import com.gl.battleship.services.Constants;
import com.gl.battleship.services.exceptions.MessagesExceptions;
import com.gl.battleship.services.exceptions.UserException;

/**
 * Manager for users
 * 
 * @author mariana.capponetto
 * @author romina.tornello
 * @version 1.0
 * 
 */

@Service 
@Scope("singleton")
public class UserManager implements IUserManager{
	/**
	 * Map with key SecurityTocken
	 */
	private Map<String, User> users = new HashMap<String, User>();
	/**
	 * Map with key nick 
	 */
	
		
	/**
	 * Login 
	 * 
	 * @param user is the user name who want to enter in the game 
	 * @param password is the password who want to enter in the game
	 * @return securityToken is an string that identified the user
	 * @throws UserException if securityToken or user already logged 
	 */
	public String logIn(String username, String password) throws UserException{
		User user= new User();
				
		String securityToken = "token" + Math.round((Math.random() * 100));
		if(!validateNick(username)){
			user.setNick(username);
				user.setStateUser(UserState.AVAILABLE);
				user.setSessionState(true);
				user.setLastActivity(new Date());
				this.users.put(securityToken,user);	
				
		}
		else{
				throw new UserException(MessagesExceptions.USER_ALREADY_LOGGED);		
		}
		return securityToken;
	}
	
	
	/**
	 * Gets an user
	 * 
	 * @param securityToken security token of the user.
	 * @return an user.
	 * @throws UserException unless the user exists.
	 */	
	public User getUser(String securityToken) throws UserException {
		 
		if(validateToken(securityToken)){
			User user = this.users.get(securityToken);
		
			return user;
		}else{
			throw new UserException(MessagesExceptions.INVALID_SECURITYTOKEN);

		}
		
	}

	
	/**
	 * LogOut 
	 * 
	 * @param securityToken is the String that identified the user
	 * @return 'VALID' is an String that confirms the user unlogged
	 * @throws UserException if the securityToken doesn't exit
	 */	
	public String logOut(String securityToken) throws UserException{  
		  if(validateToken(securityToken)){
		   User user = users.get(securityToken);
		   String nick = user.getNick();
		   this.users.remove(securityToken);
		   NotificationManager.removeNotificationByNick(nick);
		  }else{
		   throw new UserException(MessagesExceptions.INVALID_SECURITYTOKEN);
		  }	  
		  return Constants.LOGOUT_SUCCESSFUL; 
		 }
	
	
	/**
	 * List the users for states
	 * 
	 * @param securityToken is the security token of the user that requires the list
	 * @param userState is the state of the user list required: ALL,AVAILABLE,NOTAVAILABLE
	 * @return List of users for the state required 
	 * @throws UserException if the securityToken doesn't exit
	 * 
	 */
	public List<User> listUsersByState(String securityToken, UserState userState)throws UserException{
		
		List<User> usersList = new ArrayList<User>();
		User user= new User();
		if(validateToken(securityToken)){			
			Iterator us = users.entrySet().iterator();
			while (us.hasNext()) {
			Map.Entry usuario = (Map.Entry)us.next();		
			if(!(usuario.getKey().equals(securityToken))){
			user=(User) usuario.getValue();
				if(userState.equals(UserState.ALL)){
						usersList.add(user);
					}else{
						if(((User)usuario.getValue()).getStateUser().equals(userState)){
							usersList.add(user);
						}	
					}
				}
			}
			}else{
				   throw new UserException(MessagesExceptions.INVALID_SECURITYTOKEN);
			  }	  
		return usersList;			
		}
	
	
	/**
	 * List of the active users that his session unexpired 
	 * 
	 * @return List of active users 
	 * 
	 */	
	public List<User> listActiveUsers()throws UserException{
		
		List<User> usersList = new ArrayList<User>();	
		User user= new User();			
		Iterator it = users.entrySet().iterator();
			while (it.hasNext()) {
			Map.Entry us = (Map.Entry)it.next();	
			user=(User) us.getValue();
			long lastActivity=user.getLastActivity().getTime();
			long now=new Date().getTime();
			long diferent=now-lastActivity;			
			if((user.getSessionState()).equals(true) &&(diferent<=900000)){		//to check decrease the time,900000=15minutos		
						usersList.add(user);						
						}
				}		
			return usersList;			
			}
	
	/**
	 * 
	 * Get User By Nick
	 * @param nick is the nick user
	 * @return user 
	 * @throws UserException if the nick doesn't exist
	 * 
	 */
	public User getUserByNick(String nick) throws UserException {
		User user= new User();
		Iterator it = users.entrySet().iterator();
		while (it.hasNext()) {
			Map.Entry e = (Map.Entry)it.next();
			if (nick.equals(((User)e.getValue()).getNick())){
				user = (User)e.getValue();
			}	
		}

		return user;
	}
	
	
	/**
	 * Remove the inactive users 
	 * 
	 */		
	public void removeInactiveUsers(){
		User user= new User();			
		Iterator it = users.entrySet().iterator();
			while (it.hasNext()) {
			Map.Entry us = (Map.Entry)it.next();	
			user=(User) us.getValue();
			long lastActivity=user.getLastActivity().getTime();	
			long now=new Date().getTime();
			long diferent=now-lastActivity;	
			String securityToken=(String) us.getKey();
				if((user.getSessionState()).equals(false)||(diferent>900000)){		//to check decrease the time,900000=15minutos		
					this.users.remove(securityToken);
					}
				}		
			}


	/**
	 * Validate the security token
	 * 
	 * @param securityToken to be validate
	 * @return true or false
	 */
	public boolean validateToken(String securityToken){
		    return users.containsKey(securityToken);  
		 }
	
	
	/**
	 * Validate the user nick
	 * 
	 * @param nick to be validate
	 * @return true or false
	 */
	public boolean validateNick(String nick)throws UserException{
		User user=getUserByNick(nick);
		return users.containsValue(user);		
	}
}